package com.qdlc.p2p.biz.service.impl;

import javax.annotation.Resource;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.qdlc.p2p.biz.executer.AbstractExecuter;
import com.qdlc.p2p.biz.executer.ExecuterHelper;
import com.qdlc.p2p.biz.executer.impl.DeductRechargeFeeExecuter;
import com.qdlc.p2p.biz.executer.impl.OnlineRechargeSuccessExecuter;
import com.qdlc.p2p.biz.service.AccountService;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.LogFactory;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper.Nid;
import com.qdlc.p2p.dal.common.model.jpa.PageDataList;
import com.qdlc.p2p.dal.dao.AccountCashDao;
import com.qdlc.p2p.dal.dao.AccountDao;
import com.qdlc.p2p.dal.dao.AccountLogDao;
import com.qdlc.p2p.dal.dao.AccountRechargeDao;
import com.qdlc.p2p.dal.dto.Account;
import com.qdlc.p2p.dal.dto.AccountRecharge;
import com.qdlc.p2p.dal.dto.Pay;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.model.AccountModel;
import com.qdlc.p2p.dal.util.SystemConfigs;

@Service("accountService")
public class AccountServiceImpl implements AccountService {

    /** 交易log */
    private static Logger tradeLogger = LogFactory.TRADE_LOGGER;

    @Resource
    private AccountDao accountDao;

    @Resource
    private AccountRechargeDao accountRechargeDao;

    @Resource
    private AccountCashDao accountCashDao;

    @Resource
    private AccountLogDao accountLogDao;

    @Override
    public void updateAccount(Account account) {
        accountDao.update(account);
    }

    @Override
    public void updateAccountByUserId(long userId, double total, double useMoney, double noUseMoney) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal(); // 变更前总金额
        double preUseMoney = account.getUseMoney(); // 变更前可用金额
        double preNoUseMoney = account.getNoUseMoney(); // 变更前冻结金额

        double afterTotal = BigDecimalUtil.add(preTotal, total); // 变更后总金额
        double afterUseMoney = BigDecimalUtil.add(preUseMoney, useMoney); // 变更后可用金额
        double afterNoUseMoney = BigDecimalUtil.add(preNoUseMoney, noUseMoney); // 变更前冻结金额

        account.setTotal(afterTotal); // 总金额
        account.setUseMoney(afterUseMoney); // 可用金额
        account.setNoUseMoney(afterNoUseMoney); // 冻结金额

        // 更新
        accountDao.update(account);
        tradeLogger.info(String.format("accountDao::updateAccountByUserId 用户ID[%d] 总金额[%f --> %f] 可用金额[%f --> %f] 冻结金额[%f --> %f]",
                userId, preTotal, afterTotal, preUseMoney, afterUseMoney, preNoUseMoney, afterNoUseMoney));
    }

    @Override
    public synchronized void newRecharge(String orderId, String returnText, Pay pay) {
        AccountRecharge existRecharge = accountRechargeDao.getRechargeByTradeno(orderId);
        if (existRecharge == null) {
            return;
        }
        if (existRecharge.getStatus() == 0 || existRecharge.getStatus() == 2) {
            // 修改订单状态
            existRecharge.setStatus(1);
            existRecharge.setReturnMsg(returnText);
            accountRechargeDao.update(existRecharge);

            // 资金记录表
            Global.setTransfer("recharge", existRecharge);
            Global.setTransfer("user", existRecharge.getUser());
            AbstractExecuter executer = ExecuterHelper.getExecuter(OnlineRechargeSuccessExecuter.class);
            executer.execute(existRecharge.getMoney(), existRecharge.getUser(), new User(SystemConfigs.ADMIN_ID));

            double recharge_fee = getRechargeFee(pay);
            if (recharge_fee > 0) {
                double fee = BigDecimalUtil.mul(existRecharge.getMoney(), recharge_fee);
                if (fee >= 0.01) {
                    existRecharge.setFee(fee);
                    accountRechargeDao.updateRechargeFee(fee, existRecharge.getId());
                    Global.setTransfer("payment", "");
                    Global.setTransfer("deduct", fee);
                    executer = ExecuterHelper.getExecuter(DeductRechargeFeeExecuter.class);
                    executer.execute(fee, existRecharge.getUser());
                }
            }
        }
    }

    private double getRechargeFee(Pay pay) {
        double recharge_fee = 0.00;
        if (pay != null) {
            recharge_fee = SystemConfigHelper.getDoubleValue(Nid.RECHARGE_FEE);
        }
        return recharge_fee;
    }

    @Override
    public int updateSinaProfit(Account account) {
        long accountId = account.getId();
        Account oldAccount = accountDao.findByUserId(accountId);

        double preYesterdayBonus = oldAccount.getYesterdayBonus(); // 变更前新浪昨日收益
        double preTotalBonus = account.getTotalBonus(); // 变更前新浪总收益

        double afterYesterdayBonus = account.getYesterdayBonus(); // 变更后新浪昨日收益
        double afterTotalBonus = account.getTotalBonus();// 变更后新浪总收益

        long userId = account.getUserId();
        int result = accountDao.updateSinaProfit(accountId, afterYesterdayBonus, afterTotalBonus);
        if (1 == result) {
            tradeLogger.info(String.format("accountDao::updateSinaProfit 用户ID[%d] 新浪昨日收益[%f --> %f] 新浪总收益[%f --> %f]",
                    userId, preYesterdayBonus, preTotalBonus, afterYesterdayBonus, afterTotalBonus));
        } else {
            tradeLogger.info(String.format("accountDao::updateSinaProfit 更新用户ID[%d]新浪收益异常, 需要进行的操作：新浪昨日收益[%f --> %f] 新浪总收益[%f --> %f]",
                    userId, preYesterdayBonus, preTotalBonus, afterYesterdayBonus, afterTotalBonus));
        }
        return result;
    }

    @Override
    public void addUseMoneyAndTotal(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal();    // 变更前总金额
        double preUseMoney = account.getUseMoney(); // 变更前可用金额

        double afterTotal = BigDecimalUtil.add(preTotal, amount); // 变更后总金额
        double afterUseMoney = BigDecimalUtil.add(preUseMoney, amount); // 变更后可用金额

        account.setTotal(afterTotal);// 总金额
        account.setUseMoney(afterUseMoney);// 可用金额

        // 更新
        accountDao.updateTotalAndUseMoney(account);
        tradeLogger.info(String.format("accountDao::addUseMoney 用户ID[%d] 总金额[%f --> %f] 可用金额[%f --> %f] 变更金额[%f]",
                userId, preTotal, afterTotal, preUseMoney, afterUseMoney, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void freeze(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preUseMoney = account.getUseMoney(); // 变更前可用金额
        double preNoUseMoney = account.getNoUseMoney(); // 变更前冻结金额

        double afterUseMoney = BigDecimalUtil.sub(preUseMoney, amount); // 变更后可用金额
        double afterNoUseMoney = BigDecimalUtil.add(preNoUseMoney, amount); // 变更后冻结金额

        account.setUseMoney(afterUseMoney);// 可用金额
        account.setNoUseMoney(afterNoUseMoney); // 冻结金额

        accountDao.updateUseMoneyAndNoUseMoney(account);

        tradeLogger.info(String.format("accountDao::freeze 用户ID[%d] 可用金额[%f --> %f] 冻结金额[%f --> %f]变更金额[%f]",
                userId, preUseMoney, afterUseMoney, preNoUseMoney, afterNoUseMoney, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void unFreeze(long userId, long toUserId, double amount) {
        freeze(userId, toUserId, -amount);
    }

    @Override
    public void deductUseMoneyAndTotal(long userId, long toUserId, double amount) {
        addUseMoneyAndTotal(userId, toUserId, -amount);
    }

    @Override
    public void deductNoUseMoneyAndTotal(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal(); // 变更前总金额
        double preNoUseMoney = account.getNoUseMoney(); // 变更前冻结金额

        double afterTotal = BigDecimalUtil.sub(preTotal, amount);    // 变更后总金额
        double afterNoUseMoney = BigDecimalUtil.sub(preNoUseMoney, amount); // 变更冻结金额

        account.setTotal(afterTotal);// 总金额
        account.setNoUseMoney(afterNoUseMoney);// 冻结金额

        // 更新
        accountDao.updateTotalAndNoUseMoney(account);
        tradeLogger.info(String.format("accountDao::deductNoUseMoney 用户ID[%d] 总金额[%f --> %f] 冻结金额[%f --> %f] 变更金额[%f]",
                userId, preTotal, afterTotal, preNoUseMoney, afterNoUseMoney, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void addCollectionAndTotal(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal();// 变更前总金额
        double preCollection = account.getCollection(); // 变更前待收金额

        double afterTotal = BigDecimalUtil.add(preTotal, amount); // 变更后总金额
        double afterCollection = BigDecimalUtil.add(preCollection, amount); // 变更后待收金额

        account.setTotal(afterTotal);// 总金额
        account.setCollection(afterCollection); // 待收金额

        // 更新
        accountDao.updateTotalAndCollection(account);
        tradeLogger.info(String.format("accountDao::addCollection 用户ID[%d] 总金额[%f --> %f] 代收金额[%f --> %f] 变更金额[%f]",
                userId, preTotal, afterTotal, preCollection, afterCollection, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void deductCollectionAndTotal(long userId, long toUserId, double amount) {
        addCollectionAndTotal(userId, toUserId, -amount);
    }

    @Override
    public void revokeCapital(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preUseMoney = account.getUseMoney(); // 变更前可用金额
        double preCollection = account.getCollection();// 变更前待收金额

        double afterUseMoney = BigDecimalUtil.add(preUseMoney, amount); // 变更后可用金额
        double afterCollection = BigDecimalUtil.sub(preCollection, amount);// 变更后待收金额

        account.setUseMoney(afterUseMoney); // 可用金额
        account.setCollection(afterCollection); // 待收金额

        // 更新
        accountDao.updateUseMoneyAndCollection(account);
        tradeLogger.info(String.format("accountDao::revokeCapital 用户ID[%d] 待收金额[%f --> %f] 可用金额[%f --> %f] 变更金额[%f]",
                userId, preCollection, afterCollection, preUseMoney, afterUseMoney, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void revokeInterest(long userId, long toUserId, double amount) {
        revokeCapital(userId, toUserId, amount);
    }

    @Override
    public void revokeInterestManageFee(long userId, Long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal();// 变更前总金额
        double afterTotal = BigDecimalUtil.sub(preTotal, amount); // 变更后总金额
        double preCollection = account.getCollection();// 变更前待收金额
        double afterCollection = BigDecimalUtil.sub(preCollection, amount);// 变更后待收金额

        account.setTotal(afterTotal); // 可用金额
        account.setCollection(afterCollection); // 待收金额

        // 更新
        accountDao.updateTotalAndCollection(account);
        tradeLogger.info(String.format("扣除利息管理费 用户ID[%d] 待收金额[%f --> %f] 总金额[%f --> %f] 变更金额[%f]", userId, preCollection, afterCollection, preTotal, afterTotal, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void revokeCapital(long userId, long toUserId, double useMoney, double collection) {
        Account account = accountDao.findByUserId(userId);

        double preUseMoney = account.getUseMoney(); // 变更前可用金额
        double preCollection = account.getCollection();// 变更前待收金额

        double afterUseMoney = BigDecimalUtil.add(preUseMoney, useMoney); // 变更后可用金额
        double afterCollection = BigDecimalUtil.sub(preCollection, collection);// 变更后待收金额

        account.setUseMoney(afterUseMoney); // 可用金额
        account.setCollection(afterCollection); // 待收金额

        // 更新
        accountDao.updateUseMoneyAndCollection(account);
        tradeLogger.info(String.format("accountDao::revokeCapital 用户ID[%d] 待收金额[%f --> %f] 可用金额[%f --> %f] 变更金额[%f]",
                userId, preCollection, afterCollection, preUseMoney, afterUseMoney, useMoney));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, useMoney);
    }

    @Override
    public void revokeCapitalAndTotal(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal();// 变更前总金额
        double preUseMoney = account.getUseMoney(); // 变更前可用金额
        double preCollection = account.getCollection();// 变更前待收金额

        double afterTotal = BigDecimalUtil.add(preTotal, amount); // 变更后总金额
        double afterUseMoney = BigDecimalUtil.add(preUseMoney, amount); // 变更后可用金额
        double afterCollection = BigDecimalUtil.sub(preCollection, amount);// 变更后待收金额

        account.setTotal(afterTotal); // 总金额
        account.setUseMoney(afterUseMoney); // 可用金额
        account.setCollection(afterCollection); // 待收金额

        // 更新
        accountDao.update(account);
        tradeLogger.info(String.format("accountDao::revokeCapitalAndTotal 用户ID[%d] 总金额[%f --> %f]  待收金额[%f --> %f] 可用金额[%f --> %f] 变更金额[%f]",
                userId, preTotal, afterTotal, preCollection, afterCollection, preUseMoney, afterUseMoney, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void deductNoUseMoneyAndAddCollection(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preNoUseMoney = account.getNoUseMoney(); // 变更前冻结金额
        double preCollection = account.getCollection(); // 变更前待收金额

        double afterNoUseMoney = BigDecimalUtil.sub(preNoUseMoney, amount); // 变更前冻结金额
        double afterCollection = BigDecimalUtil.add(preCollection, amount);// 变更后待收金额

        account.setNoUseMoney(afterNoUseMoney); // 冻结金额
        account.setCollection(afterCollection); // 代收金额

        // 更新
        accountDao.updateNoUseMoneyAndCollection(account);
        tradeLogger.info(String.format("accountDao::deductNoUseMoneyAndAddCollection 用户ID[%d] 冻结金额[%f --> %f] 代收金额[%f --> %f] 变更金额[%f]",
                userId, preNoUseMoney, afterNoUseMoney, preCollection, afterCollection, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public void deductTotalAndAddCollection(long userId, long toUserId, double amount) {
        Account account = accountDao.findByUserId(userId);

        double preTotal = account.getTotal(); // 变更前总金额
        double preCollection = account.getCollection(); // 变更前待收金额

        double afterTotal = BigDecimalUtil.sub(preTotal, amount); // 变更后总金额
        double afterCollection = BigDecimalUtil.add(preCollection, amount);// 变更后待收金额

        account.setTotal(afterTotal); // 总金额
        account.setCollection(afterCollection); // 代收金额

        // 更新
        accountDao.updateTotalAndCollection(account);
        tradeLogger.info(String.format("accountDao::deductTotalAndAddCollection 用户ID[%d] 总金额[%f --> %f] 代收金额[%f --> %f] 变更金额[%f]",
                userId, preTotal, afterTotal, preCollection, afterCollection, amount));

        // 增加资金变更log
        accountLogDao.addAccountLog(account, toUserId, amount);
    }

    @Override
    public Account findAccountByUserId(long userId) {
        return accountDao.findByUserId(userId);
    }

    @Override
    public double findUseMoneyByUserId(long userId) {
        return accountDao.findUseMoneyByUserId(userId);
    }

    @Override
    public PageDataList<AccountModel> list(AccountModel model) {
        return accountDao.list(model);
    }

    @Override
    public double sumAllUseMoney() {
        return accountDao.sumAllUseMoney();
    }

    @Override
    public double[] getCashFeeByYear(String year) {
        double[] CashFee = new double[12];
        String date;
        for (int i = 0; i < 12; i++) {
            date = year + (i > 8 ? "-" : "-0") + (i + 1);
            double cashFee = accountCashDao.getCashFeeByDate(date);
            CashFee[i] = cashFee;
        }
        return CashFee;
    }

    @Override
    public Account findById(long id) {
        return accountDao.findById(id);
    }

    @Override
    public double sumUseMoney() {
        return accountDao.sumUseMoney();
    }
}